package com.chuangke.file.service.impl;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.jodconverter.core.DocumentConverter;
import org.jodconverter.core.document.DefaultDocumentFormatRegistry;
import org.jodconverter.core.office.OfficeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.chuangke.common.constant.ElasticIndexConstants;
import com.chuangke.common.constant.Masks;
import com.chuangke.common.exception.ChuangkeException;
import com.chuangke.common.utils.SpringContextUtil;
import com.chuangke.elasticsearch.model.ElasticEntity;
import com.chuangke.elasticsearch.service.ElasticsearchService;
import com.chuangke.file.model.FileDbank;
import com.chuangke.file.model.FileDocument;
import com.chuangke.file.model.FileInfo;
import com.chuangke.file.model.FileType;
import com.chuangke.file.service.FileDbankService;
import com.chuangke.file.service.FileHandleService;
import com.chuangke.file.service.FileInfoService;
import com.chuangke.file.service.FileQueryService;
import com.chuangke.file.util.ImageUtils;
import com.chuangke.file.util.TikaUtil;
import com.chuangke.fss.FSSClient;
import com.chuangke.fss.FSSConfig;
import com.chuangke.fss.model.FSSObject;

/**
 * @author stm
 * @date 2020-08-18
 */
@Service
public class FileHandleServiceImpl implements FileHandleService {

	private static final Logger logger = LoggerFactory.getLogger(FileHandleServiceImpl.class);

//	@Autowired
//	private DocumentConverter documentConverter;//改成通过getDocumentConverter()获取，主要是为了停用转换，报错的问题。
	@Autowired
	private FSSClient fssClient;
	@Autowired
	private FSSConfig fssConfig ;

//	@Autowired
//	private ElasticsearchService baseElasticService;
//	@Autowired
//	private ElasticsearchRestTemplate esRestTemplate;
//	@Autowired
//	private ElasticsearchService elasticsearchService ;
	@Autowired
	private FileInfoService fileService;
	@Autowired
	private FileDbankService fileDbankService;
	@Autowired
	private FileQueryService fileQueryService;
	
	private DocumentConverter getDocumentConverter() {
		return SpringContextUtil.getBean(DocumentConverter.class) ;
	}

	@Async
	@Override
	public void handle(FileInfo file) {
		// 1 为文件生成缩率图
		String[] storages = createThumb(file);
		file.setThumStatus(storages[0]);
		file.setThumStorage1(storages[1]);
		file.setThumStorage2(storages[2]);

		//是否将内容放入Elasticsearch
		if(fssConfig.isOpenElasticsearch) {
			// 2 将文档类型的文件内容解析出来，放到elasticsearch
			// 2.1 解析文件内容
			String contentText = parseContent(file.getContent());
			FileDocument docoument = convertMeta(file);
			docoument.setContent(contentText);

			// 2.2 将文件内容放入elasticsearch
			ElasticEntity<FileDocument> elasticEntity = new ElasticEntity<>();
			elasticEntity.setId(file.getId());
			elasticEntity.setData(docoument);
//			elasticsearchService.insertDocument(ElasticIndexConstants.FILE_INDEX, elasticEntity);
			
			file.setIndexStatus(Masks.BOOL_YES);
		}

		fileService.updateHandleInfo(file);
	}

	private String[] createThumb(FileInfo file) {
		byte[] content = file.getContent();
		// 1.1 如果文件的类型非pdf类型的文档，将文件转换成pdf文档
		byte[] imgContent = content;
		String imageMimeType = file.getMimeType();
		if (Arrays.asList(FileType.DOC_MIME_TYPE).contains(file.getMimeType())) {
			//正常应该用jodconverter.local.enabled这个配置
			if(!fssConfig.isOpenElasticsearch) {
				return new String[] { Masks.BOOL_NO, "", "" };
			}
			imgContent = convertToPdf(content);
			imageMimeType = FileType.pdf.getMime();
		}

		// 1.2 根据文件生成缩率图
		byte[] thumbnail = createThumbnail(imageMimeType, imgContent);
		// 1.3 将缩率图存储到文件系统
		if (thumbnail == null || thumbnail.length == 0) {
			return new String[] { Masks.BOOL_NO, "", "" };
		}

		FSSObject fssObject = new FSSObject();
		fssObject.setSuffix("jpg");
		fssObject.setObjectContent(thumbnail);
		fssObject.setSize(thumbnail.length);
		fssObject.setMd5hex(DigestUtils.md5Hex(thumbnail));
		fssObject.setStorage2("thumb/" + fssObject.getMd5hex());// 指定存储地址，minio上传到缩率图目录
		fssObject.setMimeType(TikaUtil.getMimeType(content));
		fssObject = fssClient.getFss(file.getStorageType()).upload(fssObject);

		return new String[] { Masks.BOOL_YES, fssObject.getStorage1(), fssObject.getStorage2() };
	}

	@Override
	public byte[] convertToPdf(byte[] content) {
		byte[] outbyte = null;
		try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
			DocumentConverter documentConverter = getDocumentConverter() ;
			documentConverter.convert(new BufferedInputStream(new ByteArrayInputStream(content))).to(output)
					.as(DefaultDocumentFormatRegistry.PDF).execute();
			outbyte = output.toByteArray();

//			FileUtils.writeByteArrayToFile(new File("D:\\fss\\a.pdf"), outbyte);
//			FileUtils.writeByteArrayToFile(new File("D:\\fss\\a.jpg"), ImageUtils.createThumbnailByPdf(outbyte));

		} catch (Exception e) {
			throw new ChuangkeException(e);
		}
		return outbyte;
	}

	@Override
	public void convertToPdf(File source, File target) {
		try {
			DocumentConverter documentConverter = getDocumentConverter() ;
			documentConverter.convert(source).to(target).execute();
		} catch (OfficeException e) {
			throw new ChuangkeException(e);
		}
	}

	@Override
	public byte[] createThumbnail(String mimeType, byte[] content) {
		if (FileType.pdf.getMime().equals(mimeType)) {
			return ImageUtils.createThumbnailByPdf(content);
		}

		if (Arrays.asList(FileType.IMG_MIME_TYPE).contains(mimeType)) {
			return ImageUtils.createThumbnailByImage(content);
		}
		return null;
	}

	@Override
	public String parseContent(byte[] content) {
		if (ArrayUtils.isEmpty(content)) {
			return "";
		}

		try {
			return TikaUtil.getContent(content);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return "";
		}
	}

	@Override
	public FileDocument convertMeta(FileInfo fileInfo) {
		FileDbank dbank = fileDbankService.loadDbankById(fileInfo.getDbankId());

		FileDocument document = new FileDocument();
		document.setId(fileInfo.getId());
		document.setTitle(fileInfo.getName());
		document.setVersion(fileInfo.getVersion());
		document.setSuffix(fileInfo.getSuffix() != null ? fileInfo.getSuffix().toLowerCase() : null);
		document.setMimeType(fileInfo.getMimeType());
		document.setSize(fileInfo.getSize());
		document.setMd5hex(fileInfo.getMd5hex());
		document.setDbankId(fileInfo.getDbankId());
		document.setDbankBelongId(dbank.getBelongId());
		document.setDbankBelongType(dbank.getType());
		document.setDownloadCount(fileInfo.getDownloadCount());
		document.setDownloadPeopleCount(fileInfo.getDownloadPeopleCount());
		document.setIsPublish(fileInfo.getIsPublish());
		document.setRemarks(fileInfo.getRemarks());
		document.setCreatedAt(fileInfo.getCreatedAt());
		document.setCreatedBy(fileInfo.getCreatedBy());
		document.setUpdatedAt(fileInfo.getUpdatedAt());
		document.setUpdatedBy(fileInfo.getUpdatedBy());

		return document;
	}

	@Async
	@Override
	public void updateElasticByFileInfo(List<FileInfo> files) {
		files.forEach(fileInfo->{
			if(!fssConfig.isOpenElasticsearch) {
				return ;
			}
			
			FileDocument docoument = convertMeta(fileInfo);
			
//			FileDocument esDocoument = elasticsearchService.getDocument(ElasticIndexConstants.FILE_INDEX, fileInfo.getId(), FileDocument.class) ;
			
//			if(esDocoument != null) {
//				docoument.setContent(esDocoument.getContent());
//			}
			
			ElasticEntity<FileDocument> elasticEntity = new ElasticEntity<>();
			elasticEntity.setId(fileInfo.getId());
			elasticEntity.setData(docoument);
			
//			esRestTemplate.delete(docoument.getId(), FileDocument.class);
//			esRestTemplate.save(docoument) ;
//			elasticsearchService.updateDocument(ElasticIndexConstants.FILE_INDEX, elasticEntity, FileDocument.class) ;
		});
	}
	
	@Async
	@Override
	public void updateElasticByFileId(List<String> fileIds) {
		List<FileInfo> files = new ArrayList<>() ;
		fileIds.forEach(fileId-> files.add(fileQueryService.load(fileId)));
		updateElasticByFileInfo(files) ;
	}

}
